/* Copyright (c) 2016-2020 Enfry Ltd. All Rights Reserved.
 * 
 * This software is the confidential and proprietary information of Enfry. 
 * You shall not disclose such Confidential Information
 * and shall use it only in accordance with the terms of the agreements
 * you entered into with Enfry.
 */
package com.enfry.common.util;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import com.enfry.common.util.String.Strings;
import com.enfry.common.util.array.Arrays;
import com.enfry.common.util.array.Types;
import com.enfry.common.util.asserts.Asserts;
import com.enfry.common.util.constants.TypeConstants;
import com.enfry.common.util.validate.Validates;

/**
 * 
 *
 * @version v1.0.0 @author zouzhigang 2014-3-21 新建与整理
 */
/**
 * 类相关工具类 
 * @Title com.enfry.util.Classes
 * @author Penghu
 * @date 2016年11月29日
 */

public class Classes implements TypeConstants
{
    /*************************************************************/
    //新建对象
    /*************************************************************/
    
    /**
     * 通过类名获取类结构
     * 
     * @param className 类名
     * @return Class<?> 类结构
     */
    public static Class<?> forName(String className)
    {
        try
        {//先在当前ClassLoader尝试,以保证不是系统默认的父ClassLoader优先
            return Class.forName(className, true, Thread.currentThread().getContextClassLoader());
        }
        catch(Exception e)
        {//ClassNotFoundException时再全局查一次
            try{return Class.forName(className);}
            catch (Throwable e1){return null;}
        }
        catch (Throwable e) 
        {//NoClassDefFoundError时直接返回null，一般是引用了其他jar的类，但jar未导入
            return null;
        }
    }
    
    /**
     * 初始化实例，忽略异常，异常时返回null
     * @param className 类名
     * @return          实例
     */
    public static Object newInstance(String className)
    {
        try
        {
            Class<?> clazz = forName(className);
            if (clazz == null)
                return null;
            
            return clazz.newInstance();
        }
        catch (Exception e)
        {
            return null;
        }
    }
    
    /**
     * 初始化实例，忽略异常，异常时返回null
     * 
     * @param clazz     类结构
     * @return          实例
     */
    public static <T> T newInstance(Class<T> clazz)
    {
        try{return clazz.newInstance();}catch (Exception e){return null;}
    }
    
    /**
     * 初始化定义成FNew的实例，如果异常则使用IllegalArgumentException强制抛出
     * 
     * @param clazz     类结构
     * @return          实例
     */
    public static <T> T newInstanceAnNew(Class<T> clazz)
    {
        Asserts.assertNotNull(clazz, "参数不能为NULL");
        try{return clazz.newInstance();}catch (Exception e){throw Asserts.exception("["+clazz.getName()+"]定义成注解[@AnNew]类型但不支持[newInstance]");}
    }
    
    /**
     * 初始化数组，先创建数组对象，再转化为对象数组，基本类型转为对象类型，如int[]转为Integer[]
     * 
     * @param clazz     类结构
     * @param length    数组长度
     * @return          对象数组
     */
    public static Object[] newInstance(Class<?> clazz, int length)
    {
        Object obj = Array.newInstance(clazz, length);
        return Arrays.toArray(obj);
    }
    
    /**
     * 通过类结构分析集合，得到一个集合对象，当前仅支持
     * 1.Collection.class,List.class,ArrayList.class返回ArrayList对象
     * 2.LinkedList.class返回LinkedList对象
     * 3.Set.class,HashSet.class返回HashSet对象
     * 
     * @param clazz 类结构
     * @return      集合对象
     */
    public static Collection<Object> newList(Class<?> clazz)
    {
        Collection<Object> list = null;
        if (clazz == Collection.class || clazz == List.class || clazz == ArrayList.class)
            list = new ArrayList<Object>();
        else if (clazz == LinkedList.class)
            list = new LinkedList<Object>();
        else if (clazz == Set.class || clazz == HashSet.class)
            list = new HashSet<Object>();
        //else其他不支持，直接返回null;
       
        return list;
    }
    
    /**
     * 通过类结构分析MAP，得到一个MAP对象，当前仅支持
     * 1.Map.class,HashMap.class，返回HashMap对象
     * 2.ConcurrentMap.class,ConcurrentHashMap.class，返回ConcurrentHashMap对象
     * 3.Hashtable.class返回Hashtable对象
     * 4.LinkedHashMap.class，返回LinkedHashMap对象
     * 5.TreeMap.class，返回TreeMap对象
     * 
     * @param clazz 类结构
     * @return      MAP对象
     */
    public static Map<String, Object> newMap(Class<?> clazz)
    {
        Map<String, Object> map = null;
        if (clazz == Map.class || clazz == HashMap.class)
            map = new HashMap<String, Object>();
        else if (clazz == ConcurrentMap.class || clazz == ConcurrentHashMap.class)
            map = new ConcurrentHashMap<String, Object>();
        else if (clazz == Hashtable.class)
            map = new Hashtable<String, Object>();
        else if (clazz == LinkedHashMap.class)
            map = new LinkedHashMap<String, Object>();
        else if (clazz == TreeMap.class)
            map = new TreeMap<String, Object>();
        //else不支持的类型
        
        return map;
    }
    
    /**
     * 通过类结构和参数表组装成实例
     * 
     * @param clazz                     类结构
     * @param paramMap                  参数表
     * @return                          组装成对象
     * @throws IllegalAccessException   非法访问异常
     */
    public static <T> T newInstance(Class<T> clazz, Map<String, String> paramMap) throws IllegalAccessException
    {
        T obj = null;
        try{obj = clazz.newInstance();}catch(Exception e){throw Asserts.exception("类["+clazz+"]不支持无参数实例化");}
        
        List<Field> fields = Classes.getFieldListDeep(clazz);
        for (Field field : fields)
        {
            String value = paramMap.get(field.getName());
            if (value == null)
            {//前端没有参数的过滤
                continue;
            }
            
            Class<?> type = field.getType();
            if (!Types.isPrimitive(type) && !Types.isPrimitiveArray(type) && type != String.class && type != String[].class)
            {//不支持的属性先过滤，仅支持8个基本类型和基本类型数组、字符串、字符串数组
                continue;
            }
            
            field.setAccessible(true);
            switch (type.getName().hashCode())
            {
            case BOOLEAN_CODE:
            case BOOLEAN_OBJ_CODE:
            {//布尔型
                if ("true".equalsIgnoreCase(value) || "1".equalsIgnoreCase(value))
                    field.setBoolean(obj, true);
                else
                    field.setBoolean(obj, false);
                break;
            }
            case BYTE_CODE:
            case BYTE_OBJ_CODE:
            {//字节型
                if (Validates.isInteger(value))
                    field.setByte(obj, Byte.parseByte(value));
                break;
            }
            case CHAR_CODE:
            case CHAR_OBJ_CODE:
            {//字符型
                if (value.length() == 1)
                    field.setChar(obj, value.charAt(0));
                break;
            }
            case SHORT_CODE:
            case SHORT_OBJ_CODE:
            {//短整型
                if (Validates.isInteger(value))
                    field.setShort(obj, Short.parseShort(value));
                break;
            }
            case INT_CODE:
            case INT_OBJ_CODE:
            {//整型
                if (Validates.isInteger(value))
                    field.setInt(obj, Integer.parseInt(value));
                break;
            }
            case LONG_CODE:
            case LONG_OBJ_CODE:
            {//长整型
                if (Validates.isInteger(value))
                    field.setLong(obj, Long.parseLong(value));
                break;
            }
            case FLOAT_CODE:
            case FLOAT_OBJ_CODE:
            {//浮点型
                if (Validates.isFloat(value))
                    field.setFloat(obj, Float.parseFloat(value));
                break;
            }
            case DOUBLE_CODE:
            case DOUBLE_OBJ_CODE:
            {//双字节浮点型
                if (Validates.isFloat(value))
                    field.setDouble(obj, Double.parseDouble(value));
                break;
            }
            case STRING_CODE:
            {//字符串
                field.set(obj, value);
                break;
            }
            //以下为数组
            case BOOLEAN_ARR_CODE:
            {//布尔型数组
                boolean[] values = Arrays.toBooleanArrayForm(value, ",");
                field.set(obj, values);
                break;
            }
            case BYTE_ARR_CODE:
            {//字节型数组，指定是UTF-8格式
                if (value.length() > 0)
                    field.set(obj, Strings.getBytesUTF8(value));
                break;
            }
            case CHAR_ARR_CODE:
            {//字符型数组
                if (value.length() > 0)
                    field.set(obj, value.toCharArray());
                break;
            }
            case SHORT_ARR_CODE:
            {//短整型数组
                if (Validates.isInteger(value))
                    field.set(obj, Arrays.toShortArray(value));
                break;
            }
            case INT_ARR_CODE:
            {//整型数组
                if (Validates.isInteger(value))
                    field.set(obj, Arrays.toIntArray(value));
                break;
            }
            case LONG_ARR_CODE:
            {//长整型数组
                if (Validates.isInteger(value))
                    field.set(obj, Arrays.toLongArray(value));
                break;
            }
            case FLOAT_ARR_CODE:
            {//浮点型数组
                if (Validates.isFloat(value))
                    field.set(obj, Arrays.toFloatArray(value));
                break;
            }
            case DOUBLE_ARR_CODE:
            {//双字节浮点型数组
                if (Validates.isFloat(value))
                    field.set(obj, Arrays.toDoubleArray(value));
                break;
            }
            case STRING_ARR_CODE:
            {//字符串数组
                field.set(obj, Arrays.toStringArray(value));
                break;
            }
            }
        }
        
        return obj;
    }
    
    /*************************************************************/
    //判断类结构相关
    /*************************************************************/
    
    /**
     * 判断类结构，是否实现指定的接口
     * 
     * @param clazz     类结构
     * @param iface     接口
     * @return          =true表示实现,=false表示未实现
     */
    public static boolean isImplement(Class<?> clazz, Class<?> iface)
    {
        if (iface == null || clazz == null || clazz == Object.class || Types.isPrimitiveBase(clazz) || !iface.isInterface())
            return false;
        
        if (clazz == iface)
            return true;
        
        //先判断接口是否实现，或实现的接口是否继承
        for (Class<?> c : clazz.getInterfaces())
        {
            while (c != iface)
            {//如果未实现，再继承查找，直到没有继承
                Class<?>[] cs = c.getInterfaces();
                if (cs.length == 0)
                    break;
                
                c = cs[0];
            }
            
            //最后判断是否实现
            if (c == iface)
                return true;
        }
        
        //再判断继承是否实现接口
        Class<?> c = clazz.getSuperclass();
        while(c != Object.class)
        {
            if (isImplement(c, iface))
                return true;
            
            c = c.getSuperclass();
        }
        
        return false;
    }
    
    /**
     * 判断一个类是否是集合类
     * 
     * @param clazz 类结构
     * @return      =true表示真
     */
    public static boolean isCollection(Class<?> clazz)
    {
        return isImplement(clazz, Collection.class);
    }
    
    /**
     * 判断一个类是否是映射表类
     * 
     * @param clazz 类结构
     * @return      =true表示真
     */
    public static boolean isMap(Class<?> clazz)
    {
        return isImplement(clazz, Map.class);
    }
    
    /**
     * 判断是否是静态方法
     * 
     * @param method 方法
     * @return =true表示是，=false表示不是
     */
    public static boolean isStaticMethod(Method method)
    {
        return (method.getModifiers() & Modifier.STATIC) != 0;
    }
    
    /**
     * 判断是否是静态属性
     * 
     * @param field 属性
     * @return =true表示是，=false表示不是
     */
    public static boolean isStaticField(Field field)
    {
        return (field.getModifiers() & Modifier.STATIC) != 0;
    }
    
    /**
     * 判断是否是临时属性
     * 
     * @param field 属性
     * @return =true表示是，=false表示不是
     */
    public static boolean isTransientField(Field field)
    {
        return (field.getModifiers() & Modifier.TRANSIENT) != 0;
    }
    
    /**
     * 判断是否是静态属性或临时属性
     * 
     * @param field 属性
     * @return =true表示是，=false表示不是
     */
    public static boolean isStaticTransientField(Field field)
    {
        return (field.getModifiers() & Modifier.STATIC) != 0 || (field.getModifiers() & Modifier.TRANSIENT) != 0;
    }
    
    /**
     * 获取类中指定的属性，该方法仅支持查询本类定义的属性
     * 
     * @param clazz 类结构
     * @param name 属性名称
     * @return 属性对应的结构 =null表示未查找，!=null表示查到
     */
    public static Field getField(Class<?> clazz, String name)
    {
        try
        {
            return clazz.getDeclaredField(name);
        }
        catch (Exception e) 
        {
            return null;
        }
    }
    
    /**
     * 获取类中指定的属性，支持深度查找，即如果没有则向上查询父类的属性
     * 
     * @param clazz 类结构
     * @param name 属性名称
     * @return 属性对应的结构 =null表示未查找，!=null表示查到
     */
    public static Field getFieldDeep(Class<?> clazz, String name)
    {
        Field field = getField(clazz, name);
        while (field == null)
        {
            if (clazz == Object.class || clazz.getSuperclass() == Object.class)
                break;
            
            clazz = clazz.getSuperclass();
            field = getField(clazz, name);
        }
        
        return field;
    }
    
    /**
     * 获取指定对象的字段值，异常抛unchecked异常
     * 
     * @param obj       对象
     * @param field     对象字段
     * @return          返回字段值
     */
    public static Object getFieldValue(Object obj, Field field)
    {
        Asserts.assertNotNull(field, "参数[field]不能为null");
        
        try{field.setAccessible(true);return field.get(obj);}
        catch (Exception e){throw Asserts.exception(e);}
    }
    
    /**
     * 设置指定对象的字段值，异常抛unchecked异常
     * 
     * @param obj       对象
     * @param field     对象字段
     * @param value     值
     */
    public static void setFieldValue(Object obj, Field field, Object value)
    {
        Asserts.assertNotNull(field, "参数[field]不能为null");
        
        try{field.setAccessible(true);field.set(obj, value);}
        catch (Exception e){throw Asserts.exception(e);}
    }
    
    /**
     * 获取类中指定的字段列表，支持深度查找父类的字段列表(父类的循递归查找),静态和临时两种属性不拷贝
     * 
     * @param clazz 类
     * @return      返回字段列表，静态和临时除外
     */
    public static List<Field> getFieldListDeep(Class<?> clazz)
    {
        List<Field> fieldList = new ArrayList<Field>();
        getFieldListDeep(clazz, fieldList);
        return fieldList;
    }
    
    /**
     * 获取类中指定的属性列表，支持深度查找父类的字段列表(父类的循递归查找),静态和临时两种属性不拷贝
     * 
     * @param clazz 类
     * @param fieldList 用于存储的字段列表
     */
    public static void getFieldListDeep(Class<?> clazz, List<Field> fieldList)
    {
        Field[] fieldArr = clazz.getDeclaredFields();
        for (Field field : fieldArr)
        {
            int mod = field.getModifiers();
            if (Modifier.isStatic(mod) || Modifier.isTransient(mod) || "this$0".equals(field.getName()))
                continue;//静态和临时两种属性不拷贝，内部类指向外部类的引用不拷贝
            
            fieldList.add(field);
        }
        
        Class<?> superSrcClass = clazz.getSuperclass();
        if (superSrcClass != null && superSrcClass != Object.class)
        {
            getFieldListDeep(superSrcClass, fieldList);
        }
    }
}
